package com.hotspot.chartview.view;

import java.util.ArrayList;
import java.util.List;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Scroller;

import com.hotspot.chartview.R;
import com.hotspot.chartview.model.BarChartData;

/**
 * 自定义柱状图
 * 
 * @author BaiYuliang
 */
public class BarChart extends View {

    /**
     * BarChart的监听
     */
    public interface BarChartListener {

        /**
         * 当中间显示条目发生变化时的回调
         * 
         * @param barChartData
         *            当前选中的条目
         */
        public void onCenterViewChanged(BarChartData barChartData);
    }

    private static final String TAG = "BarChart";

    /**
     * 从xml中读取的参数
     */
    private int mLineNum; // 行数
    private int mColumnNum; // 列数
    private int mDataViewMaxLineNum; // 数据View最多可显示的行数
    private int mCellWidth; // 单元格宽度
    private int mCellHeight; // 单元格高度
    private int mLineColor; // 网格颜色
    private int mTitleBg; // 标题栏背景
    private int mTitleTextColor; // 标题栏文字颜色
    private int mTitleTextSize; // 标题栏文字大小
    private int mCenterViewColor; // 中间View颜色
    private int mDataViewColor; // 数据View颜色
    private String mDataEmptyHint; // 空数据时标题显示的文字

    private Paint mPaintTitle; // 标题的颜色
    private Paint mPaintCenter; // 画中间位置用的笔
    private Paint mPaintLine; // 画线用的笔
    private Paint mPaintData; // 画内容用的笔

    private int mCenterViewLeft; // 中间位置
    private int mDataViewLeftBorder;// 内容显示区域的左边界
    private int mDataViewLeft; // 内容显示的最左边位置

    private int mLastTouchX; // 点击位置的X坐标
    private int mLastTouchY; // 点击位置的Y坐标
    private int mTouchSlop; // 滑动距离的阈值
    private Scroller mScroller;

    private Bitmap mTitleBitmap; // 标题栏图片
    private int mTitleBitmapWidth; // 标题栏宽
    private int mTitleBitmapHeight; // 标题栏高

    private List<BarChartData> mBarChartDatas = new ArrayList<BarChartData>(); // 要显示的内容
    private float mDataMaxHeight; // 最大数据的值

    private BarChartListener mBarChartListener; // 柱状图的监听器

    public BarChart(Context context) {
        this(context, null, 0);
    }

    public BarChart(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BarChart(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        if (attrs != null) {
            Resources resources = getResources();
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BarChart);
            mLineNum = typedArray.getInteger(R.styleable.BarChart_line_num, 9);
            mColumnNum = typedArray.getInteger(R.styleable.BarChart_column_num, 15);
            mDataViewMaxLineNum = typedArray.getInteger(
                    R.styleable.BarChart_data_view_max_line_num, 9);
            mCellWidth = typedArray.getDimensionPixelSize(R.styleable.BarChart_cell_width, 0);
            mCellHeight = typedArray.getDimensionPixelSize(R.styleable.BarChart_cell_height, 0);
            mLineColor = typedArray.getColor(R.styleable.BarChart_line_color,
                    resources.getColor(R.color.bar_chart_line_color_default));
            mTitleBg = typedArray.getResourceId(R.styleable.BarChart_title_bg,
                    R.drawable.bar_chart_title_bg);
            mTitleTextColor = typedArray.getColor(R.styleable.BarChart_title_text_color,
                    resources.getColor(R.color.bar_chart_title_text_color_default));
            mTitleTextSize = typedArray.getDimensionPixelSize(R.styleable.BarChart_title_text_size,
                    28);
            mCenterViewColor = typedArray.getColor(R.styleable.BarChart_center_view_color,
                    resources.getColor(R.color.bar_chart_center_view_color_default));
            mDataViewColor = typedArray.getColor(R.styleable.BarChart_data_view_color,
                    resources.getColor(R.color.bar_chart_data_view_color_default));
            mDataEmptyHint = typedArray.getString(R.styleable.BarChart_data_empty_hint);
            typedArray.recycle();
        }

        init(context); // 初始化一些参数
    }

    /**
     * 初始化一些参数
     */
    private void init(Context context) {
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        mScroller = new Scroller(context);
        mTitleBitmap = BitmapFactory.decodeResource(context.getResources(), mTitleBg);
        mTitleBitmapWidth = mTitleBitmap.getWidth();
        mTitleBitmapHeight = mTitleBitmap.getHeight();
        Log.i(TAG, "mTitleBitmapWidth = " + mTitleBitmapWidth + ", mTitleBitmapHeight = "
                + mTitleBitmapHeight);

        /**
         * 创建画标题用的画笔
         */
        mPaintTitle = new Paint();
        mPaintTitle.setColor(mTitleTextColor);
        mPaintTitle.setTextSize(mTitleTextSize);
        mPaintTitle.setTextAlign(Align.CENTER);

        /**
         * 创建画中间位置用的画笔
         */
        mPaintCenter = new Paint();
        mPaintCenter.setColor(mCenterViewColor);
        mPaintCenter.setStrokeWidth(1);

        /**
         * 创建划线的画笔
         */
        mPaintLine = new Paint();
        mPaintLine.setColor(mLineColor);
        mPaintLine.setStrokeWidth(1);

        /**
         * 创建画内容的画笔
         */
        mPaintData = new Paint();
        mPaintData.setColor(mDataViewColor);
        mPaintData.setStrokeWidth(1);
    }

    /**
     * 初始化单元格格的大小和位置
     */
    private void initCellSizeAndPosition() {
        int width = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
        if (mCellWidth == 0) {
            mCellWidth = width / mColumnNum;
        }
        if (mCellHeight == 0) {
            mCellHeight = width / mColumnNum;
        }

        // 中间View的位置
        mCenterViewLeft = getPaddingLeft() + mColumnNum / 2 * mCellWidth;
        // 内容View的最左边位置
        mDataViewLeft = mDataViewLeftBorder = mCenterViewLeft - (mBarChartDatas.size() - 1)
                * mCellWidth;

        // 设置自定义View的高度
        getLayoutParams().height = mTitleBitmapHeight + mCellHeight * mLineNum + 1;

        /**
         * 内容的最大值
         */
        mDataMaxHeight = 0;
        for (BarChartData barChartData : mBarChartDatas) {
            if (barChartData.height > mDataMaxHeight) {
                mDataMaxHeight = barChartData.height;
            }
        }

        Log.i(TAG, "mCellWidth = " + mCellWidth + ", mCellHeight = " + mCellHeight
                + ", mDataViewLeft = " + mDataViewLeft + ", mBarChartDatas.size() = "
                + mBarChartDatas.size() + ", mDataViewLeftBorder = " + mDataViewLeftBorder
                + ", mDataViewLeft = " + mDataViewLeft + ", mDataMaxHeight = " + mDataMaxHeight);
    }

    /**
     * 画中间位置
     * 
     * @param canvas
     *            画布
     * @param paint
     *            画笔
     */
    private void drawCenterView(Canvas canvas, Paint paint) {
        // 画标题
        drawTitle(canvas);

        // 画中间位置
        int top = getPaddingTop() + mTitleBitmapHeight;
        int bottom = top + mCellHeight * mLineNum;
        canvas.drawRect(mCenterViewLeft, top, mCenterViewLeft + mCellWidth, bottom, mPaintCenter);
    }

    /**
     * 画标题
     * 
     * @param canvas
     *            画布
     */
    private void drawTitle(Canvas canvas) {
        // 画标题栏背景
        canvas.drawBitmap(mTitleBitmap, (getMeasuredWidth() - mTitleBitmapWidth) / 2, 0, null);

        /**
         * 计算当前中间位置的柱状图内容
         */
        BarChartData barChartData = null;
        if (mBarChartDatas.size() > 0) {
            int position = (mDataViewLeft - mDataViewLeftBorder) / mCellWidth;
            int maxPosition = mBarChartDatas.size() - 1;
            if (position >= maxPosition) {
                position = maxPosition;
            } else if (position <= 0) {
                position = 0;
            }
            position = maxPosition - position;
            Log.i(TAG, "position = " + position);
            barChartData = mBarChartDatas.get(position);
        }

        // 画标题栏文字
        String title = mDataEmptyHint;
        if (barChartData != null) {
            title = barChartData.title;
        }
        int left = (getMeasuredWidth() - mTitleBitmapWidth) / 2;
        Rect targetRect = new Rect(left, 0, left + mTitleBitmapWidth, mTitleBitmapHeight);
        FontMetricsInt fontMetrics = mPaintTitle.getFontMetricsInt();
        int baseLine = targetRect.top
                + (targetRect.bottom - targetRect.top - fontMetrics.bottom + fontMetrics.top) / 2
                - fontMetrics.top;
        canvas.drawText(title, targetRect.centerX(), baseLine, mPaintTitle);

        if (mBarChartListener != null && barChartData != null) {
            mBarChartListener.onCenterViewChanged(barChartData);
        }
    }

    /**
     * 画内容
     * 
     * @param canvas
     *            画布
     * @param paint
     *            画笔
     */
    private void drawGridViewDatas(Canvas canvas, Paint paint) {
        int top = getPaddingTop() + mTitleBitmapHeight;
        int bottom = top + mCellHeight * mLineNum;
        int left = mDataViewLeft;
        for (int i = 0; i < mBarChartDatas.size(); i++) {
            BarChartData barChartData = mBarChartDatas.get(i);
            float height = barChartData.height * mCellHeight * mDataViewMaxLineNum / mDataMaxHeight;
            Log.i(TAG, "left = " + left + ", bottom = " + bottom + ", height = " + height);
            canvas.drawRect(left, bottom - height, left + mCellWidth, bottom, mPaintData);
            left += mCellWidth;
        }
    }

    /**
     * 画网格
     * 
     * @param canvas
     *            画布
     */
    private void drawGridCell(Canvas canvas, Paint paint) {
        /**
         * 画横线
         */
        int startY = getPaddingTop() + mTitleBitmapHeight;
        for (int i = 0; i <= mLineNum; i++) {
            canvas.drawLine(getPaddingLeft(), startY, mCellWidth * mColumnNum - getPaddingRight(),
                    startY, paint);
            startY += mCellHeight;
        }

        /**
         * 画竖线
         */
        int startX = getPaddingLeft();
        int top = mTitleBitmapHeight;
        for (int i = 0; i <= mColumnNum; i++) {
            if (i == mColumnNum) {
                startX -= 1;
            }
            canvas.drawLine(startX, top, startX, top + mCellHeight * mLineNum, paint);
            startX += mCellWidth;
        }
    }

    /**
     * 滑动到特定位置
     */
    private void scrollToDestination() {
        /**
         * 限制左右边界
         */
        if (mDataViewLeft < mDataViewLeftBorder) {
            mDataViewLeft = mDataViewLeftBorder;
        }
        if (mDataViewLeft > mCenterViewLeft) {
            mDataViewLeft = mCenterViewLeft;
        }

        /**
         * 计算滑动的方向及距离
         */
        int delta = mDataViewLeft % mCellWidth;
        int distance = 0;
        if (delta < 0) {
            if (Math.abs(delta) >= mCellWidth / 2) {
                distance = -(mCellWidth + delta);
            } else {
                distance = -delta;
            }
        } else {
            if (Math.abs(delta) >= mCellWidth / 2) {
                distance = mCellWidth - delta;
            } else {
                distance = -delta;
            }
        }

        // 使用Scroller让滑动流畅
        mScroller.startScroll(mDataViewLeft, 0, distance, 0, Math.abs(distance) * 5);
        invalidate();
    }

    /**
     * 是否可以滑动
     * 
     * @param event
     *            MotionEvent
     * @return true:可以滑动;false:不能滑动
     */
    private boolean canScroll(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            int deltaX = x - mLastTouchX;
            int deltaY = y - mLastTouchY;
            if (Math.abs(deltaX) > mTouchSlop && Math.abs(deltaX) > Math.abs(deltaY)) {
                return true;
            }
        }
        return false;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        initCellSizeAndPosition(); // 初始化单元格大小和初始位置
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawCenterView(canvas, mPaintCenter); // 画中间位置
        drawGridViewDatas(canvas, mPaintData); // 画内容
        drawGridCell(canvas, mPaintLine); // 画网格
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "onTouchEvent");
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mLastTouchX = x;
            mLastTouchY = y;
            break;
        case MotionEvent.ACTION_MOVE:
            if (canScroll(event)) {
                mDataViewLeft += (x - mLastTouchX);
                mLastTouchX = x;
                mLastTouchY = y;
                invalidate();
            }
            break;
        case MotionEvent.ACTION_UP:
            scrollToDestination();
            break;
        }
        return true;
    }

    /**
     * 调用Scroller.startScroll方法后，需要复写该回调方法来产生滑动效果
     */
    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            mDataViewLeft = mScroller.getCurrX();
            Log.i(TAG, "computeScroll mDataViewLeft = " + mDataViewLeft);
            invalidate();
        }
    }

    /**
     * 设置内容
     * 
     * @param barChartDatas
     *            内容
     */
    public void setBarChartData(List<BarChartData> barChartDatas) {
        mBarChartDatas.clear();
        if (barChartDatas != null && barChartDatas.size() > 0) {
            mBarChartDatas.addAll(barChartDatas);
        }
        initCellSizeAndPosition();
        invalidate();
    }

    /**
     * 设置柱状图的监听器
     * 
     * @param listener
     *            监听器
     */
    public void setBarChartListener(BarChartListener listener) {
        mBarChartListener = listener;
    }

    /**
     * 获取单元格宽度
     * 
     * @return 单元格宽度
     */
    public int getCellWidth() {
        return mCellWidth;
    }

    /**
     * 获取单元格高度
     * 
     * @return 单元格高度
     */
    public int getCellHeight() {
        return mCellHeight;
    }

}
